package com.padakeji.android.ui.widget;

import android.content.Context;
import android.os.Handler;
import android.os.Message;
import android.support.annotation.NonNull;
import android.support.v7.widget.GridLayoutManager;
import android.support.v7.widget.LinearLayoutManager;
import android.support.v7.widget.RecyclerView;
import android.support.v7.widget.StaggeredGridLayoutManager;
import android.util.AttributeSet;
import android.util.Log;
import android.view.LayoutInflater;
import android.view.View;

import com.padakeji.android.ui.R;

/**
 * Created by atanl on 2015/10/23.
 */
public class AutoLoadRecycler extends RecyclerViewX {

    private static final String TAG = "AutoLoadRecycler";

    public static abstract class AutoLoadListener<T>  {
        public abstract T loadInBackground();
        final void finished(Object result) {
            onFinished((T) result);
        }
        public abstract void onFinished(T result);
        final void fail(Object exception) {
            onFail((Throwable) exception);
        }
        public abstract void onFail(Throwable e);
    }

    private MyOnScrollListener mOnScrollListener;

    public void setAutoLoadListener(AutoLoadListener<?> autoLoadListener) {
        mOnScrollListener.setAutoLoadListener(autoLoadListener);
    }

    private static final int MESSAGE_WHAT_START = 0;
    private static final int MESSAGE_WHAT_SUCCESS = 1;
    private static final int MESSAGE_WHAT_FAILURE = 2;

    private Handler mHandler = new Handler(new Handler.Callback() {
        @Override
        public boolean handleMessage(Message msg) {
            switch (msg.what) {
                case MESSAGE_WHAT_START:
                    addLoadingView();
                    break;
                case MESSAGE_WHAT_SUCCESS:
                    removeLoadingView();
                    if (mOnScrollListener != null) {
                        mOnScrollListener.autoLoadListener.finished(msg.obj);
                    }
                    break;
                case MESSAGE_WHAT_FAILURE:
                    removeLoadingView();
                    if (mOnScrollListener != null) {
                        mOnScrollListener.autoLoadListener.fail(msg.obj);
                    }
                    break;
                default:
                    break;
            }
            return true;
        }
    });

    private View loadingView;

    public AutoLoadRecycler(Context context) {
        super(context);
        init();
    }

    public AutoLoadRecycler(Context context, AttributeSet attrs) {
        this(context, attrs, 0);
    }

    public AutoLoadRecycler(Context context, AttributeSet attrs, int defStyle) {
        super(context, attrs, defStyle);
        init();
    }

    private void init() {
        mOnScrollListener = new MyOnScrollListener(mHandler);
        addOnScrollListener(mOnScrollListener);
        loadingView = LayoutInflater.from(getContext()).inflate(R.layout.padaui_auto_load_recycler_loading, null, false);
    }

    public void enableAutoLoad() {
        mOnScrollListener.isAutoLoadEnable = true;
    }

    public void disableAutoLoad() {
        mOnScrollListener.isAutoLoadEnable = false;
    }

    public void setLoadingView(View v) {
        this.loadingView = v;
    }

    private void addLoadingView() {
        addFooterView(loadingView);
    }

    private void removeLoadingView() {
        removeFooterView(loadingView);
    }

    private static class MyOnScrollListener extends OnScrollListener {

        boolean isAutoLoadEnable = true;
        private Boolean isLoading = false;
        AutoLoadListener<?> autoLoadListener;
        private Handler mHandler;

        public void setAutoLoadListener(AutoLoadListener<?> l) {
            this.autoLoadListener = l;
        }

        public MyOnScrollListener(@NonNull Handler handler) {
            if (handler == null) {
                throw new RuntimeException("A handler must be passed as a parameter for constructor.");
            }
            mHandler = handler;
        }

        @Override
        public void onScrollStateChanged(RecyclerView recyclerView, int newState) {
            super.onScrollStateChanged(recyclerView, newState);
        }

        @Override
        public void onScrolled(RecyclerView recyclerView, int dx, int dy) {
            if (!isAutoLoadEnable) {
                return;
            }
            synchronized (isLoading) {
                if (isLoading) {
                    return;
                }
                final AutoLoadRecycler mRecycler = (AutoLoadRecycler) recyclerView;
                LayoutManager layoutManager = mRecycler.getLayoutManager();
                LayoutManagerType t = getLayoutManageType(layoutManager);
                if (t == null) {
                    Log.d(TAG, "LayoutManage has not been set, please set it first.");
                }
                switch (t) {
                    case Linear:
                        LinearLayoutManager linearLayoutManager = (LinearLayoutManager) layoutManager;
                        int lastVisibleItemPosition = linearLayoutManager.findLastVisibleItemPosition();
                        int itemCount = linearLayoutManager.getItemCount();
                        if (itemCount - lastVisibleItemPosition < 3) {
                            new Thread(new Runnable() {
                                @Override
                                public void run() {
                                    if (autoLoadListener != null) {
                                        isLoading = true;
                                        Message startLoadingMsg = new Message();
                                        startLoadingMsg.what = MESSAGE_WHAT_START;
                                        mHandler.sendMessage(startLoadingMsg);
                                        try {
                                            Object r = autoLoadListener.loadInBackground();
                                            Message finishedMsg = new Message();
                                            finishedMsg.what = MESSAGE_WHAT_SUCCESS;
                                            finishedMsg.obj = r;
                                            mHandler.sendMessage(finishedMsg);
                                        } catch (Throwable e) {
                                            Message failedMsg = new Message();
                                            failedMsg.what = MESSAGE_WHAT_FAILURE;
                                            failedMsg.obj = e;
                                            mHandler.sendMessage(failedMsg);
                                        } finally {
                                            isLoading = false;
                                        }
                                    }
                                }
                            }).start();
                        }
                        break;
                    default:
                        break;

                }
            }

        }

        public LayoutManagerType getLayoutManageType(LayoutManager layoutManager) {
            if (layoutManager == null) {
                return null;
            }
            if (layoutManager instanceof LinearLayoutManager) {
                return LayoutManagerType.Linear;
            } else if (layoutManager instanceof GridLayoutManager) {
                return LayoutManagerType.Grid;
            } else if (layoutManager instanceof StaggeredGridLayoutManager) {
                return LayoutManagerType.StaggeredGrid;
            } else {
                throw new RuntimeException("Unsupported LayoutManager used. Valid ones are LinearLayoutManager, GridLayoutManager and StaggeredGridLayoutManager.");
            }
        }

    }

    private enum LayoutManagerType {
        Linear,
        Grid,
        StaggeredGrid,
    }


}
